import dict4ini
import os
import re
import time
import traceback

from ini import *
		
#=============================
#=         User Tools        =
#=============================
#======
#= User Names
def getcleanname(x):
	"Converts a user@domain/resource to simply a user name."
	server = core["required"]["domain"]
	x = unicode(x)
	if '/' in x:
		x = x[:x.find("/")]
	if '@' in x and x[x.find('@'):] == "@" + server:
		x = x[:x.find("@")]
	return x.lower()

def getdisplayname(x):
	"Converts a user@domain/resource to a displayable nick"
	server = core["required"]["domain"]
	x = unicode(x)
	x = autocomplete(x)
	if '/' in x:
		x = x[:x.find("/")]
	if hasnick(x):
		x = nick.inuse[x]
		x = x.capitalize()
		if isadmin(getjid(x)):
			pass#x = '_'+ x +'_'
	if '%' in x and 'msn.jabber' in x[x.find('%'):]:
		x = x[:x.find('%')]
	if '@' in x and x[x.find('@'):] == "@" + server:
		x = x[:x.find("@")]
	return x

def getjid(x):
	"returns a full jid from a display name"
	server = core["required"]["domain"]
	x = getcleanname(autocomplete(x)).lower()
	if x in nick.registered.keys():
		x = nick.registered.get(x)
	elif x in nick.temp.keys():
		x = nick.temp.get(x)
	elif '@' not in x:
		x = x + "@" + server
	return x
		
#======
#= User Flags
def has_userflag(jid,key,flag):
	"return true if the user is a userflag"
	jid = getjid(jid)
	if userlist[jid].has_key(key):
		return flag in userlist[jid][key]
	return 0

def add_userflag(jid,key,flag):
	"add an flag to a user, return 0 if they already have that flag"
	jid = getjid(jid)
	if has_userflag(jid,key,flag):
		return 0
	if not userlist.has_key(jid) or not userlist[jid].has_key(key):
		userlist[jid][key] = [flag]
	else:
		userlist[jid][key].append(flag)
	saveuserlist()
	
def del_userflag(jid,key,flag):
	"del an flag, return 0 if they didn't have the flag"
	jid = getjid(jid)
	if not has_userflag(jid,key,flag):
		return 0
	userlist[jid][key].remove(flag)
	if userlist[jid][key] == []:
		del userlist[jid][key]
	saveuserlist()
	return 1

def set_userflag(jid,key,flag):
	"set an flag, remove all existed flag"
	userlist[getjid(jid)][key] = [flag]
	saveuserlist()
	return 1

#======
#= Database Commands
def has_dbentry(section,key,entry):
	"Return true if the section has a key entry"
	if userlist[section].has_key(key):
		return entry in database[section][key]
	return 0

def add_dbentry(section,key,entry):
	"add an flag to a user, return 0 if they already have that flag"
	if has_dbentry(section,key,entry):
		return 0
	if not database.has_key(section) or not database[section].has_key(key):
		database[section][key] = [entry]
	else:
		database[section][key].append(entry)
	database.save()
	
def del_dbentry(section,key,entry):
	"del an flag, return 0 if they didn't have the flag"
	if has_dbentry(section,key,entry):
		return 0
	database[section][key].remove(entry)
	if database[section][key] == []:
		del database[section][key]
	database.save()
	return 1

def set_dbentry(section,key,entry):
	"set an flag, remove all existed flag"
	database[section][key] = [entry]
	database.save()
	return 1


	
#======
#= Rank Commands
def isadmin(jid):	return has_userflag(jid,"rank","admin")
def addadmin(jid):	return add_userflag(jid,"rank","admin")
def deladmin(jid):	return del_userflag(jid,"rank","admin")
def ismod(jid):		return has_userflag(jid,"rank","mod") or has_userflag(jid,"rank","admin")
def addmod(jid):	return add_userflag(jid,"rank","mod")
def delmod(jid):	return del_userflag(jid,"rank","mod")

#=====
#= Status Commands
def isaway(jid):  	return has_userflag(jid,"status","away")
def delaway(jid):	return del_userflag(jid,"status","away")
def addaway(jid):	return add_userflag(jid,"status","away")
def ismuted(jid):  	return has_userflag(jid,"status","muted")
def delmute(jid):	return del_userflag(jid,"status","muted")
def addmute(jid):	return add_userflag(jid,"status","muted")
def isblind(jid):  	return has_userflag(jid,"status","blind")
def delblind(jid):	return del_userflag(jid,"status","blind")
def addblind(jid):	return add_userflag(jid,"status","blind")
def isbanned(jid):	return has_userflag(jid,"status","banned")
def delban(jid):	return del_userflag(jid,"status","banned")
def addban(jid):	return set_userflag(jid,"status","banned")


#=====
#= Room Commands
def roomexists(room): 
	return room in rooms.keys()
		
def inaroom(user): return getroom()
	
def inroom(user, room): return getjid(user) in rooms[room]
def getroom(user):
	"Returns the room if a user is in one."
	user = getjid(user)
	for	(room, users) in rooms.items():
		if user in users:
			return room
			
def getmaster(room): return room_masters[room]
def ismaster(user):
	"Checks if the user is a room master and returns the room."
	user = getjid(user)
	for (room, master) in room_masters.items():
		if user in master:
			return room

#=====
#= Misc (Ordered Alphabetically)
def adduser(user):
	set_userflag(user,"last login",time.time())
	set_userflag(user,"last msg",time.time())
	#Don't ovreride an admin or mod's rank.
	if not isadmin(user) and not ismod(user):
		set_userflag(user,"rank","user")
	
def formatmessage(user, message, default, **msgparts):
	"""If you pass msgparts it will return a completed string.
Other wise it will return the unreplaced format."""
	user = getjid(user)
	if userlist[user].has_key(message + "_format"):
		format = userlist[getjid(user)][message + "_format"][0]
	else:
		format = default
	
	if msgparts:
		return format % msgparts
	return format
	
def gettarget(target):
	reason = ''
	
	if ' ' in target:
		target, reason = target.split(' ', 1)
	target = getjid(target)
	return [target, reason]

		
def hasnick(user): return nick.inuse.has_key(user)
def isplugin(args):	return args in module.system.plugins.split(" ")
def isuser(bot, user):
	"Return true if the user exists in the bot."
	user = getjid(user)
	try:
		return bot.getJidStatus(user).items() != None
	except:
		return False
		
def isonline(bot, user):
	"Return true if the user is online."
	user = getjid(user)
	try:
		return bot.getJidStatus(user).items != []
	except:
		return False


#=====================================
#=         Chat Filter Tools         =
#=====================================
def convert_seq(seq, y = None):
#======================
#= y = 1 sets the string up for the langauge filter.
#= y = 2 sets the string up to be listed in /wordfilter.
	j = None
	for i in seq:
		k = i
		if y == 1:
			k = re.sub('\[*\B\W*\]*','\W*',k)
			k = re.sub('\[(([^\]])\\\W\*([^\]]))+\]','\W*[\g<2>\g<3>]\W*',k)
			k = re.sub('\((([^\|]+)\|*([^\)]+))\)','\W*(\g<2>|\g<3>)\W*',k)
			k = re.sub('(?<!W)\*','*\W*',k)
			k = re.sub('u""','',k)		
		elif y == 2:
			k = re.sub('\Z\W*','\n',k)
		if j:			
			j += ' ' + k
		else:
			j = k
		#print j
	return j

def cuss_list():
	"Returns a formated Regex"
	core.read()
	j = convert_seq(core.optional.get("wordfilter"), y = 1)
	j = j.strip()
	j = re.sub('\s','|',j)
	#j = '(?i)(?!\\B)(' + j + ')+(\\b|\\B)'
	#Alternate, more precice way, but consumes more CPU time.
	j = '(?i)(?!\\B)(?:(?:[^aeiou](?=[^aeiou]))|(?:[aeiou](?=[aeiou])))?(' + j + ')+(?=\\b)'
	return j
	
def clean_string(string):
	'Returns a filtered string.'
	return re.sub(cuss_list(),core.optional.filtermask,string)
	
def autocomplete(msg):
	if not isinstance(msg, basestring):
		return msg
	list = re.findall('(:(\\b[^:]+\\b):)', msg)
	for (i,j) in list:
		flag = 0
		j = j.lower()
		
		for x in sortdict(nick.inuse, "value"):
			if x.lower().startswith(j):
				msg = re.sub(i,x.capitalize(),msg)
				flag = 1
		if flag:
			continue
		
		for x in sortdict(nick.registered):
			if x.lower().startswith(j):
				msg = re.sub(i,x.capitalize(),msg)
				flag = 1
		if flag:
			continue
		
		for x in sortdict(nick.temp):
			if x.lower().startswith(j):
				msg = re.sub(i,x.capitalize(),msg)
				flag = 1
		if flag:
			continue
				
		for x in sortdict(userlist):
			if x.lower().startswith(j):
				msg = re.sub(i,x.capitalize(),msg)
				flag = 1
		if flag:
			continue
				
		msg = re.sub(i,j,msg)
		msg.capitalize()
		
	return msg
	
#========================
#=         Misc         =
#========================
def sortdict(dict, item = "key"):
	s = []
	t = []
	for key, value in dict.items():
		s.append(key)
		t.append(value)
		s.sort()
		t.sort()
	if item == "key":
		return s
	elif item == "value":
		return t
	else:
		return s, t

def confirmdir(path):
	if not os.path.isdir(path):
		os.mkdir(path)
		print "ALERT: A directory doesn't exist, making folder \""+ path +"\""
	return

def get_svn_version():
	if os.path.isdir(".svn") and os.path.getsize(os.path.join(".svn","entries")) != 0:
		f = file(os.path.join(".svn","entries"))
		i = 0
		while i < 4:
			revision = f.readline()
			i = i + 1
		p = re.search('(\d+)', revision)
		try:
			core.optional.revision = int(p.group(1))
		except:
			core.optional.revision = "Unknown"
		savecore()
		f.close()
		return core.optional.revision
	elif not core.optional.revision:
		return core.optional.revision
	else:
		return 'Unknown'

def debug(tag,msg):
	"Sends a debug message to the console"
	try:
		if tag in module.system.get("debugtag"):
			print "DEBUG:",msg
	except:
		print "DEBUG:",msg

#=================================
#=         .Ini Commands         =
#=================================
def readoptionorprompt(section, option, description, config = cbot2):
	"Read an option from the general section of the config, or prompt for it"
	if not config[section].get(option):
		print description,
		config[section][option] = raw_input()

def readall(config = module, userlist = userlist, nick = nick, db = database):
	readconfig(config)
	readuserlist(userlist)
	readnicklist(nick)
	readdatabase(db)
	debug('core', "All .ini files have been sucessfully loaded.")
	
def saveall(config = module, userlist = userlist, nick = nick, db = database):
	saveconfig(config)
	saveuserlist(userlist)
	savenicklist(nick)
	savedatabase(db)
	debug('core', "All .ini files have been sucessfully saved.")

def readcore(self):
	req = core.required
	opt = core.optional
	#Set all static variables.
	req._comment = "These options are required for you to run your bot."
	req.domain = self.jid.getDomain()
	req.comment("domain","The is the domain the bot's account is on.")

	readoptionorprompt('required', "username", "What is the username (the part -before- the @ symbol) of your bot:", core)
	req.comment("username","This is the username of the bot's account.")
	readoptionorprompt('required', "password", "What is the password of your bot:", core)
	req.comment("password","This is the password of the bot's account.")
	
	opt._comment = "The bot will run fine without these options being set."
	
	opt.gui = 0
	opt.comment("gui","[Disabled for Development] Enable(1) or Disable(0) the bot's GUI.")
	
	opt.logpath = "logs"
	opt.comment("logpath","The name of the folder logs will be saved to.")
	opt.logformat = "%Y%m%d"
	opt.comment("logformat","The time format to be used as the name of the log file.")
	
	opt.wordfilter = "shit", "damn", "fuc*ke*r*","mast[eu]rbat(e|ion)"
	opt.comment("wordfilter","A list of words to be filtered out of all messages.")
	
	opt.filtermask = "****"
	opt.comment("filtermask","Any words from 'wordfilter' will be replaced by this.")
	
	core.read()
	debug('ini', "The Core Settings have been loaded.")
	
def savecore():
	try:
		core.save()
		debug('ini', "The Core Settings have been sucessfully saved.")
	except:
		traceback.print_exc()
	
def readconfig(config = module):
	if config == cbot2:
		readcbot2(config)
	
	config.read()
	debug('core', "The config for '%s' has been read." % core.required.module)

def readcbot2(config):
	system = config.system
	#symbols that must be prefixed to a message to "activate" a command.
	system._comment = "Any variables here can be changed while the bot is running."
	
	system.commandprefix = ")/!" 
	system.comment("commandprefix", "There are the characters you must being a message with to use a command. (ex. ')help')")
	
	system.debugtag = "core"
	system.comment("debugtag","Add a tag to get debug into about it")
	
	system.sysprefix = "***"
	system.comment("sysprefix", "Anything here will come at the beginning of system messages.")
	
	system.plugins = u"info user mod admin"
	system.comment("plugins","These are the plugins to be loaded.\nNew plugins should be divided by a space.")
	
	system.status = "Conference Bot v2.0"
	system.comment("status", "This is the status message for the bot.")
	return

def readtemplate(config):
	#This is a template for all config files.
	#Any varaibles in this file -must- be used.
	system = config.system
	
	system.debuglevel = "core"
	system.comment("debuglevel","Level of debugging.")
	
	system.status = "Conference Bot v2.0"
	system.comment("status", "This is the status message for the bot.")
	return

def saveconfig(config = module):
	"Saves the inuse config to disk."
	try:
		config.save()
		debug('ini', "The config has been sucessfully saved.")
	except:
		traceback.print_exc()
		
def readuserlist(userlist = userlist):
	userlist.read()
	
	debug('ini', "The userlist has been read.")
	
	for key, flags in userlist.items():
		try:
			if 'admin' in flags["rank"]: break
		except:
			del userlist[key]
	else:
		print "Input admin email account:"
		admin = raw_input().lower()
		set_userflag(admin,"rank","admin")
	
def saveuserlist(userlist = userlist):
	"Saves the userlist to disk."
	try:
		userlist.save()
		debug('ini', "The userlist has been sucessfully saved.")
	except:
		traceback.print_exc()
		
def readnicklist(nick = nick):
	nick.read()
		
def savenicklist(nick = nick):
	"Saves the nicklist to disk"
	try:	
		nick.save()
	except:
		traceback.print_exc()
		
def readdatabase(database = database):
	database.read()
	debug('ini', "The database has been read.")
		
def savedatabase(database = database):
	"Saves the database to disk"
	try:	
		database.save()
		debug('ini', "The database has been sucessfully saved.")
	except:
		traceback.print_exc()
		
